#pragma once

#include <pcap/pcap.h>

/////////////////////////////////////////////////
/// \class PacketCapture
///
/// \brief Packet capturer
///
/// \tparam PacketPacket the packet processor type, should implement the
///         <i>void operator()(const pcap_pkthdr *h, const u_char *bytes)</i> function
///
/// Capture packets and send them to the packet processor.
/////////////////////////////////////////////////
template<typename ProcessPacket>
	class PacketCapture
{
public:

	/////////////////////////////////////////////////
	/// \fn PacketCapture(ProcessPacket& processPacket)
	///
	/// Create a packet capturer with the packet processor.
	/////////////////////////////////////////////////
	PacketCapture(ProcessPacket& processPacket)
		: m_pcap(NULL)
		, m_processPacket(processPacket)
	{
	}

	virtual ~PacketCapture()
	{
		Fini();
	}

	/////////////////////////////////////////////////
	/// \fn int Init()
	/// \return Error code of this operation, zero as success.
	///
	/// Initialize the packet capturer.
	/// A packet capturer must be initialized before doing other operations.
	/////////////////////////////////////////////////
	int Init()
	{
		m_errbuf[0] = '\0';

		// Capture all the interfaces(<i>any</i> means all interfaces).
		m_pcap = pcap_create("any", m_errbuf);

		if(m_pcap == NULL)
			return -1;
		return pcap_activate(m_pcap);
	}

	/////////////////////////////////////////////////
	/// \fn int operator()()
	/// \return Error code of this operation, zero as success.
	///
	/// Begin capture packets
	/////////////////////////////////////////////////
	int operator()()
	{
		return pcap_loop(m_pcap, -1, HandlePacket, (u_char*) this);
	}

	/////////////////////////////////////////////////
	/// \fn void Stop()
	///
	/// Stop capture packets
	/////////////////////////////////////////////////
	void Stop()
	{
		pcap_breakloop(m_pcap);
	}

	void Fini()
	{
		pcap_close(m_pcap);
	}
private:

	/// The packet capture callback function.  It simply pass all information to the packet capturer
	static void HandlePacket(u_char *user, const pcap_pkthdr *h, const u_char *bytes)
	{
		PacketCapture<ProcessPacket> *self = (PacketCapture<ProcessPacket>*) user;
		self->m_processPacket(h, bytes);
	}

	pcap_t *m_pcap;						/// The handler of libpcap
	char m_errbuf[PCAP_ERRBUF_SIZE];	/// The error buffer for output of libpcap APIs
	ProcessPacket &m_processPacket;		/// The packet processor, process packets of captured
};
